﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;

namespace Roton2.TextModeEmulation
{
    /// <summary>
    /// Generates character bitmaps from glyphs.
    /// </summary>
    public class CharacterGenerator
    {
        const int GLYPH_COUNT = 256;
        const Int32 MASK_OFF = -16777216; //0xFF000000
        const Int32 MASK_ON = -1; //0xFFFFFFFF
        const Int32 MASK_DIFF = MASK_ON ^ MASK_OFF;

        int characterHeight;
        int characterLength;
        int characterWidth;
        bool doubleWidth;
        Int32[][] glyphs;
        int glyphHeight;
        int glyphWidth;
        int scaleX;

        /// <summary>
        /// Create a character generator with the given dimensions and font.
        /// </summary>
        public CharacterGenerator(byte[] font, int charWidth, int charHeight)
        {
            CharacterWidth = charWidth;
            CharacterHeight = charHeight;
            DoubleWidth = false;
            Font = font;
        }

        /// <summary>
        /// Height of a character in pixels.
        /// </summary>
        public int CharacterHeight
        {
            get
            {
                return characterHeight;
            }
            set
            {
                characterHeight = value;
                characterLength = characterHeight * characterWidth;
            }
        }

        /// <summary>
        /// Size of a character in pixels.
        /// </summary>
        public Size CharacterSize
        {
            get
            {
                return new Size(CharacterWidth, CharacterHeight);
            }
            set
            {
                CharacterWidth = value.Width;
                CharacterHeight = value.Height;
            }
        }

        /// <summary>
        /// Width of a character in pixels.
        /// </summary>
        public int CharacterWidth
        {
            get
            {
                return characterWidth;
            }
            set
            {
                characterWidth = value;
                characterLength = characterHeight * characterWidth;
            }
        }

        /// <summary>
        /// If true, characters will be generated at twice the width.
        /// </summary>
        public bool DoubleWidth
        {
            get
            {
                return doubleWidth;
            }
            set
            {
                doubleWidth = value;
                scaleX = doubleWidth ? 2 : 1;
            }
        }

        /// <summary>
        /// Raw data that contains 256 glyphs. This property is write-only.
        /// </summary>
        public byte[] Font
        {
            set
            {
                // determine glyph dimensions
                glyphs = new Int32[GLYPH_COUNT][];
                glyphWidth = 8;
                glyphHeight = ((value.Length * 8) / glyphWidth) / GLYPH_COUNT;

                // build glyphs from the raw data
                int offset = 0;
                for (int index = 0; index < GLYPH_COUNT; index++)
                {
                    int glyphDataOffset = 0;
                    glyphs[index] = new Int32[glyphHeight];

                    for (int row = 0; row < glyphHeight; row++)
                    {
                        byte glyphData = value[offset];
                        offset++;

                        for (int column = 0; column < glyphWidth; column++)
                        {
                            int maskData = ((glyphData & 0x80) != 0) ? MASK_ON : MASK_OFF;
                            glyphs[index][glyphDataOffset] = maskData;
                            glyphData <<= 1;
                            glyphDataOffset++;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Generate a character.
        /// </summary>
        public Int32[] Generate(int index, Int32 foreground, Int32 background)
        {
            Int32[] result = new Int32[characterLength * scaleX];
            int sourceIndex = 0;
            int targetIndex = 0;
            Int32[] glyphData = glyphs[index];

            for (int row = 0; row < characterHeight; row++)
            {
                for (int column = 0; column < characterWidth; column++)
                {
                    Int32 mask;

                    // obtain glyph data
                    if (column < glyphWidth)
                    {
                        mask = glyphData[sourceIndex];
                        sourceIndex++;
                    }
                    else
                    {
                        mask = MASK_OFF;
                    }

                    // repeat for the horizontal scaler
                    for (int hScaler = 0; hScaler < scaleX; hScaler++)
                    {
                        result[targetIndex] = (mask & foreground) | ((mask ^ MASK_DIFF) & background) | MASK_OFF;
                        targetIndex++;
                    }
                }
            }

            return result;
        }

        /// <summary>
        /// Height of a glyph in pixels. This property is read-only.
        /// </summary>
        public int GlyphHeight 
        { 
            get 
            { 
                return glyphHeight; 
            } 
        }

        /// <summary>
        /// Size of a glyph in pixels. This property is read-only.
        /// </summary>
        public Size GlyphSize
        {
            get
            {
                return new Size(glyphWidth, glyphHeight);
            }
        }

        /// <summary>
        /// Width of a glyph in pixels. This property is read-only.
        /// </summary>
        public int GlyphWidth
        { 
            get 
            { 
                return glyphWidth;
            } 
        }
    }
}
